﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;

using TrainingCenterSystem;
using TrainingCenterSystem.VocabularyManagement;
using TrainingCenterSystem.UserManagement;

namespace TrainingCenterSystem.TestManagement
{
    public class TestFileWriter
    {
        #region private members
        private XmlWriterSettings _settings;
        private XmlWriter _xmlWriter;
        private VocabularyTraining _vocTraining;
        #endregion        

        #region constructors
        public TestFileWriter(VocabularyTraining vocTraining, string filename)
        {
            _vocTraining = vocTraining;
            this.init(filename);
            this.writeTestFile();
        }
        #endregion

        #region methods
        /// <summary>
        /// initialises the file writer, i.e. sets default values before writing the data.
        /// </summary>
        /// <param name="filename">the filename</param>
        private void init(string filename)
        {
            _settings = new XmlWriterSettings();
            _settings.NewLineChars = Environment.NewLine;
            _settings.NewLineOnAttributes = true;
            _settings.NewLineHandling = NewLineHandling.Replace;
            _settings.NewLineOnAttributes = false;
            _settings.CloseOutput = true;
            _settings.Indent = true;
            _xmlWriter = XmlWriter.Create(filename, _settings);
        }
        

        /// <summary>
        /// the main method for writing the file.
        /// </summary>
        private void writeTestFile()
        {
            _xmlWriter.WriteStartDocument();

            // Write comments
            _xmlWriter.WriteComment("File for storing VocabularyTest or VocabularyTraining");

            if (_vocTraining is VocabularyTest)
            {
                _xmlWriter.WriteStartElement("VocabularyTest");
                this.writeTestData(true);
            }
            else
            {
                _xmlWriter.WriteStartElement("VocabularyTraining");
                this.writeTestData(false);
            }

            // write the selected sources
            this.writeSelectedSources();

            // write the questions            
            this.writeTestQuestions();

            // write the end of document
            _xmlWriter.WriteEndDocument();

            // close writer
            _xmlWriter.Close();
        }
         
        private void writeTestData(bool isTest)
        {
            // write the id
            _xmlWriter.WriteStartElement("ID", "");
            _xmlWriter.WriteString(_vocTraining.TestID);
            _xmlWriter.WriteEndElement();

            // write the name
            _xmlWriter.WriteStartElement("Name", "");
            _xmlWriter.WriteString(_vocTraining.Name);
            _xmlWriter.WriteEndElement();
            
            // write the description
            _xmlWriter.WriteStartElement("Description", "");
            string description = _vocTraining.Description;
            if (description == null)
                description = "";
            _xmlWriter.WriteString(description);
            _xmlWriter.WriteEndElement();

            // write no. of questions
            _xmlWriter.WriteStartElement("NoOfQuestions", "");
            _xmlWriter.WriteString(_vocTraining.NumberOfQuestions.ToString());
            _xmlWriter.WriteEndElement();

            // write test type
            _xmlWriter.WriteStartElement("TestType", "");
            _xmlWriter.WriteString(_vocTraining.TestType.ToString());
            _xmlWriter.WriteEndElement();
            
            // write test level
            _xmlWriter.WriteStartElement("TestLevel", "");
            _xmlWriter.WriteString(_vocTraining.TestLevel.ToString());
            _xmlWriter.WriteEndElement();

            // write test direction
            _xmlWriter.WriteStartElement("TestDirection", "");
            _xmlWriter.WriteString(_vocTraining.TestDirection.ToString());
            _xmlWriter.WriteEndElement();

            // if it is a real test, then write more attributes
            // not yet available
            /*if (isTest)
            {
            }*/
        }

        private void writeSelectedSources()
        {
            _xmlWriter.WriteStartElement("SelectedSources", "");
            for (int i = 0; i < _vocTraining.SelectedSources.Count; i++)
            {
                if (_vocTraining.SelectedSources[i] is VocabularyCollection)
                {
                    VocabularyCollection aColl = (VocabularyCollection)_vocTraining.SelectedSources[i];
                    _xmlWriter.WriteStartElement("VocabularyCollection", "");                    
                    _xmlWriter.WriteAttributeString("collID", aColl.FileName);
                    _xmlWriter.WriteString(aColl.CollectionName);
                    _xmlWriter.WriteEndElement();
                }
                else if (_vocTraining.SelectedSources[i] is VocabularyContext)
                {
                    VocabularyContext aCont = (VocabularyContext)_vocTraining.SelectedSources[i];
                    _xmlWriter.WriteStartElement("Context", "");
                    _xmlWriter.WriteAttributeString("id", aCont.ContextID);
                    _xmlWriter.WriteAttributeString("collID", aCont.CollectionID);
                    _xmlWriter.WriteString(aCont.ContextName);
                    _xmlWriter.WriteEndElement();
                }                
            }
            _xmlWriter.WriteEndElement();
        }

        private void writeTestQuestions()           
        {            
            _xmlWriter.WriteStartElement("TestQuestions", "");
            for (int i = 0; i < _vocTraining.TestQuestions.Count; i++)
            {
                if (_vocTraining.TestQuestions[i] is FreeTextQuestion)
                {
                    this.writeFreeTextQuestion((FreeTextQuestion)_vocTraining.TestQuestions[i]);
                }
                else
                {
                }
            }
            _xmlWriter.WriteEndElement();
        }

        private void writeCommonQuestionValues(string questionid,GenericWord aWord,string wordString)
        {
            // write the question-id
            _xmlWriter.WriteStartElement("QuestionID");
            _xmlWriter.WriteString(questionid);
            _xmlWriter.WriteEndElement();

            // write the word
            this.writeWord(aWord);
            
            // write the word as string
            _xmlWriter.WriteStartElement("WordString");
            _xmlWriter.WriteString(wordString);
            _xmlWriter.WriteEndElement();
        }

        private void writeFreeTextQuestion(FreeTextQuestion freetext)
        {
            _xmlWriter.WriteStartElement("FreeTextQuestion");

            // write the common/inherited values
            this.writeCommonQuestionValues(freetext.ID,freetext.TheWord,freetext.WordString);

            // write the values specific for free text questions
            _xmlWriter.WriteStartElement("ExpectedAnswer");
            _xmlWriter.WriteString(freetext.ExpectedAnswer);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteEndElement();

        }

        private void writeMultipleChoiceQuestion()
        {

        }

        private void writeWord(GenericWord aWord)
        {
            if (aWord is Noun)
            {
                this.writeNoun((Noun)aWord);
            }
            else if (aWord is Verb)
            {
                this.writeVerb((Verb)aWord);
            }
            else if (aWord is Adjective)
            {
                this.writeAdjective((Adjective)aWord);
            }
            else if (aWord is GenericWord)
            {
                this.writeGeneric(aWord);
            }
        }

        private void writeCommonWordValues(string baseValue, string translations, string collName, string contName)
        {
            _xmlWriter.WriteStartElement("BaseValue");
            _xmlWriter.WriteString(baseValue);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("Translations");
            _xmlWriter.WriteString(translations);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("CollectionName");
            _xmlWriter.WriteString(collName);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("ContextName");
            _xmlWriter.WriteString(contName);
            _xmlWriter.WriteEndElement();
        }

        /// <summary>
        /// Writes a noun
        /// </summary>
        /// <param name="noun">the noun</param>
        private void writeNoun(Noun noun)
        {
            _xmlWriter.WriteStartElement("Noun");

            this.writeCommonWordValues(noun.BaseValue, noun.Translations, noun.CollectionName, noun.ContextName);

            _xmlWriter.WriteStartElement("Article");
            _xmlWriter.WriteString(noun.Article);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("DefinedSing");
            _xmlWriter.WriteString(noun.DefinedSingular);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("DefinedPl");
            _xmlWriter.WriteString(noun.DefinedPlural);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("UndefinedSing");
            _xmlWriter.WriteString(noun.UndefinedSingular);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("UndefinedPl");
            _xmlWriter.WriteString(noun.UndefinedPlural);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteEndElement();
        }

        /// <summary>
        /// writes a verb
        /// </summary>
        /// <param name="verb">the verb</param>
        private void writeVerb(Verb verb)
        {
            _xmlWriter.WriteStartElement("Verb");

            this.writeCommonWordValues(verb.BaseValue, verb.Translations, verb.CollectionName, verb.ContextName);

            _xmlWriter.WriteStartElement("Present");
            _xmlWriter.WriteString(verb.PresentForm);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("Imperfect");
            _xmlWriter.WriteString(verb.ImperfectForm);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("Supinum");
            _xmlWriter.WriteString(verb.Supinum);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("ParticipPerfect");
            _xmlWriter.WriteString(verb.ParticipPerfect);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("IsRegular");
            _xmlWriter.WriteString(verb.IsRegular.ToString());
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteEndElement();
        }

        /// <summary>
        /// writes an adjective
        /// </summary>
        /// <param name="adj">the adjective</param>
        private void writeAdjective(Adjective adj)
        {
            _xmlWriter.WriteStartElement("Adjective");

            this.writeCommonWordValues(adj.BaseValue, adj.Translations, adj.CollectionName, adj.ContextName);

            _xmlWriter.WriteStartElement("Comparative");
            _xmlWriter.WriteString(adj.Comparative);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("Superlative");
            _xmlWriter.WriteString(adj.Superlative);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteEndElement();
        }

        /// <summary>
        /// writes a generic word
        /// </summary>
        /// <param name="gen">the generic word</param>
        private void writeGeneric(GenericWord gen)
        {
            _xmlWriter.WriteStartElement("GenericWord");
            this.writeCommonWordValues(gen.BaseValue, gen.Translations, gen.CollectionName, gen.ContextName);
            _xmlWriter.WriteEndElement();
        }

        #endregion
    }
}
